package com.sz.virtualbank.service.loan.impl;

import com.sz.virtualbank.common.exception.BusinessException;
import com.sz.virtualbank.dao.entity.LoanRecord;
import com.sz.virtualbank.dao.entity.LoanRepaymentPlan;
import com.sz.virtualbank.dao.entity.User;
import com.sz.virtualbank.dao.mapper.LoanRecordMapper;
import com.sz.virtualbank.dao.mapper.LoanRepaymentPlanMapper;
import com.sz.virtualbank.dao.mapper.UserMapper;
import com.sz.virtualbank.service.account.AccountService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 贷款还款服务实现类 - LoanServiceImpl的辅助类
 * 
 * @author Claude
 */
@Service
@Slf4j
public class LoanRepaymentService {

    @Autowired
    private LoanRecordMapper loanRecordMapper;
    
    @Autowired
    private LoanRepaymentPlanMapper loanRepaymentPlanMapper;
    
    @Autowired
    private UserMapper userMapper;
    
    @Autowired
    private AccountService accountService;

    /**
     * 提前还款
     */
    @Transactional(rollbackFor = Exception.class)
    public String earlyRepayment(Long userId, Long loanId, BigDecimal amount, String paymentPassword) {
        // 验证支付密码
        if (!accountService.verifyPayPassword(userId, paymentPassword)) {
            throw new BusinessException("支付密码错误");
        }
        
        // 获取贷款记录
        LoanRecord loanRecord = loanRecordMapper.selectById(loanId);
        if (loanRecord == null || !loanRecord.getUserId().equals(userId)) {
            throw new BusinessException("贷款记录不存在或不属于当前用户");
        }
        
        if (loanRecord.getStatus() != 1) {
            throw new BusinessException("贷款状态不正确，无法提前还款");
        }
        
        // 从账户扣款
        String tradeNo = accountService.pay(userId, amount, "LOAN_EARLY_REPAYMENT", loanId);
        
        // 将所有未还款计划标记为已还
        List<LoanRepaymentPlan> plans = loanRepaymentPlanMapper.selectByLoanId(loanId);
        for (LoanRepaymentPlan plan : plans) {
            if (plan.getStatus() == 0 || plan.getStatus() == 2) {
                loanRepaymentPlanMapper.recordPayment(plan.getId(), 
                        plan.getAmount(), 
                        1);
            }
        }
        
        // 更新贷款状态为已结清
        loanRecordMapper.updateStatus(loanId, 3);
        
        return tradeNo;
    }

    /**
     * 审批贷款
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean approveLoan(Long loanId, boolean approved, String remark) {
        LoanRecord loanRecord = loanRecordMapper.selectById(loanId);
        if (loanRecord == null) {
            throw new BusinessException("贷款记录不存在");
        }
        
        if (loanRecord.getStatus() != 0) {
            throw new BusinessException("贷款状态不正确，无法审批");
        }
        
        // 更新贷款状态
        int status = approved ? 1 : 2; // 1: 已批准, 2: 已拒绝
        loanRecordMapper.updateStatus(loanId, status);
        
        // 更新审批时间
        loanRecord.setApproveTime(LocalDateTime.now());
        loanRecord.setUpdateTime(LocalDateTime.now());
        loanRecordMapper.update(loanRecord);
        
        // 如果批准，则生成还款计划并放款
        if (approved) {
            // 生成还款计划
            generateRepaymentPlan(loanId);
            
            // 放款到用户账户
            User user = userMapper.selectById(loanRecord.getUserId());
            accountService.recharge(user.getId(), loanRecord.getAmount(), "LOAN", loanRecord.getLoanNo());
        }
        
        return true;
    }

    /**
     * 生成还款计划
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean generateRepaymentPlan(Long loanId) {
        LoanRecord loanRecord = loanRecordMapper.selectById(loanId);
        if (loanRecord == null) {
            throw new BusinessException("贷款记录不存在");
        }
        
        if (loanRecord.getStatus() != 1) {
            throw new BusinessException("贷款状态不正确，无法生成还款计划");
        }
        
        // 删除原有还款计划（如果有）
        loanRepaymentPlanMapper.deleteByLoanId(loanId);
        
        // 生成新的还款计划
        List<LoanRepaymentPlan> plans = new ArrayList<>();
        
        // 贷款金额
        BigDecimal principal = loanRecord.getAmount();
        
        // 贷款期限
        int loanTerm = loanRecord.getLoanTerm();
        
        // 月利率（年利率/12）
        BigDecimal monthlyRate = loanRecord.getInterestRate().divide(new BigDecimal("12"), 8, RoundingMode.HALF_UP)
                .divide(new BigDecimal("100"), 8, RoundingMode.HALF_UP);
        
        // 开始还款日期（假设为下个月相同日期）
        LocalDate firstRepayDate = LocalDate.now().plusMonths(1);
        
        // 根据还款方式生成还款计划
        switch (loanRecord.getRepaymentMethod()) {
            case 1: // 等额本息
                generateEqualPaymentPlan(plans, loanRecord, principal, loanTerm, monthlyRate, firstRepayDate);
                break;
            case 2: // 等额本金
                generateEqualPrincipalPlan(plans, loanRecord, principal, loanTerm, monthlyRate, firstRepayDate);
                break;
            case 3: // 一次性还本付息
                generateBulletPaymentPlan(plans, loanRecord, principal, loanTerm, monthlyRate, firstRepayDate);
                break;
            default:
                throw new BusinessException("不支持的还款方式");
        }
        
        // 保存还款计划
        loanRepaymentPlanMapper.batchInsert(plans);
        
        return true;
    }
    
    /**
     * 生成等额本息还款计划
     */
    private void generateEqualPaymentPlan(List<LoanRepaymentPlan> plans, LoanRecord loanRecord, 
                                         BigDecimal principal, int loanTerm, 
                                         BigDecimal monthlyRate, LocalDate firstRepayDate) {
        // 计算月供
        BigDecimal monthlyPayment = calculateEqualPayment(principal, monthlyRate, loanTerm);
        
        // 剩余本金
        BigDecimal remainingPrincipal = principal;
        
        for (int i = 1; i <= loanTerm; i++) {
            LoanRepaymentPlan plan = new LoanRepaymentPlan();
            plan.setLoanId(loanRecord.getId());
            plan.setPeriod(i);
            
            // 计算该期还款日期
            LocalDate dueDate = firstRepayDate.plusMonths(i - 1);
            plan.setDueDate(dueDate);
            
            // 计算该期利息
            BigDecimal interest = remainingPrincipal.multiply(monthlyRate).setScale(2, RoundingMode.HALF_UP);
            
            // 计算该期本金
            BigDecimal periodPrincipal = monthlyPayment.subtract(interest);
            if (i == loanTerm) {
                // 最后一期，处理精度问题
                periodPrincipal = remainingPrincipal;
            }
            
            plan.setAmount(monthlyPayment);
            plan.setPrincipal(periodPrincipal);
            plan.setInterest(interest);
            plan.setStatus(0); // 未还
            plan.setCreateTime(LocalDateTime.now());
            plan.setUpdateTime(LocalDateTime.now());
            
            plans.add(plan);
            
            // 更新剩余本金
            remainingPrincipal = remainingPrincipal.subtract(periodPrincipal);
        }
    }
    
    /**
     * 生成等额本金还款计划
     */
    private void generateEqualPrincipalPlan(List<LoanRepaymentPlan> plans, LoanRecord loanRecord, 
                                           BigDecimal principal, int loanTerm, 
                                           BigDecimal monthlyRate, LocalDate firstRepayDate) {
        // 每期本金
        BigDecimal periodPrincipal = principal.divide(new BigDecimal(loanTerm), 2, RoundingMode.HALF_UP);
        
        // 剩余本金
        BigDecimal remainingPrincipal = principal;
        
        for (int i = 1; i <= loanTerm; i++) {
            LoanRepaymentPlan plan = new LoanRepaymentPlan();
            plan.setLoanId(loanRecord.getId());
            plan.setPeriod(i);
            
            // 计算该期还款日期
            LocalDate dueDate = firstRepayDate.plusMonths(i - 1);
            plan.setDueDate(dueDate);
            
            // 计算该期利息
            BigDecimal interest = remainingPrincipal.multiply(monthlyRate).setScale(2, RoundingMode.HALF_UP);
            
            // 最后一期，处理精度问题
            if (i == loanTerm) {
                periodPrincipal = remainingPrincipal;
            }
            
            // 计算该期还款总额
            BigDecimal amount = periodPrincipal.add(interest);
            
            plan.setAmount(amount);
            plan.setPrincipal(periodPrincipal);
            plan.setInterest(interest);
            plan.setStatus(0); // 未还
            plan.setCreateTime(LocalDateTime.now());
            plan.setUpdateTime(LocalDateTime.now());
            
            plans.add(plan);
            
            // 更新剩余本金
            remainingPrincipal = remainingPrincipal.subtract(periodPrincipal);
        }
    }
    
    /**
     * 生成一次性还本付息还款计划
     */
    private void generateBulletPaymentPlan(List<LoanRepaymentPlan> plans, LoanRecord loanRecord, 
                                          BigDecimal principal, int loanTerm, 
                                          BigDecimal monthlyRate, LocalDate firstRepayDate) {
        // 计算利息
        BigDecimal totalInterest = principal.multiply(monthlyRate).multiply(new BigDecimal(loanTerm))
                .setScale(2, RoundingMode.HALF_UP);
        
        LoanRepaymentPlan plan = new LoanRepaymentPlan();
        plan.setLoanId(loanRecord.getId());
        plan.setPeriod(1);
        
        // 计算该期还款日期
        LocalDate dueDate = firstRepayDate.plusMonths(loanTerm - 1);
        plan.setDueDate(dueDate);
        
        // 计算该期还款总额
        BigDecimal amount = principal.add(totalInterest);
        
        plan.setAmount(amount);
        plan.setPrincipal(principal);
        plan.setInterest(totalInterest);
        plan.setStatus(0); // 未还
        plan.setCreateTime(LocalDateTime.now());
        plan.setUpdateTime(LocalDateTime.now());
        
        plans.add(plan);
    }
    
    /**
     * 计算等额本息月供
     *
     * @param principal 本金
     * @param monthlyRate 月利率
     * @param loanTerm 贷款期限（月）
     * @return 月供金额
     */
    private BigDecimal calculateEqualPayment(BigDecimal principal, BigDecimal monthlyRate, int loanTerm) {
        // 等额本息月供计算公式：本金 × 月利率 × (1+月利率)^期限 / [(1+月利率)^期限 - 1]
        BigDecimal monthlyRatePlus1 = BigDecimal.ONE.add(monthlyRate);
        BigDecimal powValue = monthlyRatePlus1.pow(loanTerm);
        
        BigDecimal numerator = principal.multiply(monthlyRate).multiply(powValue);
        BigDecimal denominator = powValue.subtract(BigDecimal.ONE);
        
        return numerator.divide(denominator, 2, RoundingMode.HALF_UP);
    }
    
    /**
     * 检查和更新逾期还款计划
     * 可以由定时任务调用
     */
    @Transactional(rollbackFor = Exception.class)
    public void checkAndUpdateOverduePlans() {
        LocalDate now = LocalDate.now();
        List<LoanRepaymentPlan> overduePlans = loanRepaymentPlanMapper.selectOverduePlans(now);
        
        for (LoanRepaymentPlan plan : overduePlans) {
            if (plan.getStatus() == 0) { // 只处理未还款的计划
                // 更新为逾期状态
                loanRepaymentPlanMapper.updateStatus(plan.getId(), 2);
                
                // 发送逾期通知（实际应用中可能需要更复杂的通知机制）
                // TODO: 通知服务
            }
        }
    }
    
    /**
     * 计算逾期费用
     *
     * @param plan 还款计划
     * @param days 逾期天数
     * @return 逾期费用
     */
    public BigDecimal calculateOverdueFee(LoanRepaymentPlan plan, int days) {
        // 示例：每日万分之五的罚息
        BigDecimal dayRate = new BigDecimal("0.0005");
        return plan.getAmount().multiply(dayRate).multiply(new BigDecimal(days)).setScale(2, RoundingMode.HALF_UP);
    }
}
